#include "general_protocol.h"

#include "../tlog/tlog.h"

#define TAG "GENERAL_PROTOCOL"
/***************************************************************************************************
 * ******************************************Define var******************************************* *
 ***************************************************************************************************/
#define protocol_one_byte_change_to_bit_size 8 /* 1byte等于8bit */

/***************************************************************************************************
 * ******************************************Define func****************************************** *
 ***************************************************************************************************/

/***************************************************************************************************
 * ****************************************Static variable**************************************** *
 ***************************************************************************************************/
static can_protocol_t *s_table_point;
static uint16_t        s_table_array_size;

/***************************************************************************************************
 * ******************************************Static func****************************************** *
 ***************************************************************************************************/
/**
 * @brief   通用协议根据can_id找寻该id在table中的下标
 * @param   uint16_t can_id
 * @retval  int32_t 返回值<0报错，返回值>=0则表示can_id在table中的下标
 * @note
 */
static int32_t protocol_find_can_id(uint16_t can_id) {
  for (int i = 0; i < s_table_array_size; i++) {
    if (can_id == s_table_point[i].can_id) {
      return i;
    }
  }
  return -1; /* 返回值为-1表示在table中没有找到对应的can_id */
}

/**
 * @brief   验证byte_number是否正确
 * @param   uint8_t byte_number
 * @retval  bool
 * @note
 */
static bool protocol_byte_number_check(uint8_t byte_number) {
  /* 因为是uint8_t的原因，所以没有负数，不做负数判断 */
  if (byte_number > 7) {  // can数据部分只有8Byte，数组下标为0-7
    return false;
  }
  return true;
}

/**
 * @brief   注册table
 * @param   can_protocol_t *table table的地址
 * @param   uint16_t table_size   table的大小
 * @retval  void
 * @note
 */
void protocol_table_reg(can_protocol_t *table, uint16_t table_size) {
  s_table_point      = table;
  s_table_array_size = (table_size / sizeof(can_protocol_t));
}

/**
 * @brief   打印table中所有的数据
 * @retval  void
 * @note
 */
void protocol_table_all_dump(void) {
  TLOGD(TAG, "table size:%d\n", s_table_array_size);
  for (size_t i = 0; i < s_table_array_size; i++) {
    TLOGI(TAG, "name:%s,can_id:%d,byte0:0X%x,byte1:0X%x,byte2:0X%x,byte3:0X%x,byte4:0X%x,byte5:0X%x,byte6:0X%x,byte7:0X%x\n",                  //
          s_table_point[i].name, s_table_point[i].can_id, s_table_point[i].frame_data.byte[0].data, s_table_point[i].frame_data.byte[1].data,  //
          s_table_point[i].frame_data.byte[2].data, s_table_point[i].frame_data.byte[3].data, s_table_point[i].frame_data.byte[4].data,        //
          s_table_point[i].frame_data.byte[5].data, s_table_point[i].frame_data.byte[6].data, s_table_point[i].frame_data.byte[7].data);
  }
}

/**
 * @brief   根据can_id从table中找到对应的数据并打印
 * @param   uint16_t can_id 需要获取哪个数据的can_id
 * @retval  bool 获取成功(true)，获取失败(false)
 * @note
 */
bool protocol_table_dump_by_can_id(uint16_t can_id) {
  int32_t protocol_table_subscript;

  protocol_table_subscript = protocol_find_can_id(can_id);
  if (protocol_table_subscript < 0) {
    TLOGI(TAG, "protocol_table_dump_by_can_id not find can_id\n");
    return false;
  }
  TLOGI(TAG, "name:%s,can_id:%d,byte0:0X%x,byte1:0X%x,byte2:0X%x,byte3:0X%x,byte4:0X%x,byte5:0X%x,byte6:0X%x,byte7:0X%x\n",                //
        s_table_point[protocol_table_subscript].name, s_table_point[protocol_table_subscript].can_id,                                      //
        s_table_point[protocol_table_subscript].frame_data.byte[0].data, s_table_point[protocol_table_subscript].frame_data.byte[1].data,  //
        s_table_point[protocol_table_subscript].frame_data.byte[2].data, s_table_point[protocol_table_subscript].frame_data.byte[3].data,  //
        s_table_point[protocol_table_subscript].frame_data.byte[4].data, s_table_point[protocol_table_subscript].frame_data.byte[5].data,  //
        s_table_point[protocol_table_subscript].frame_data.byte[6].data, s_table_point[protocol_table_subscript].frame_data.byte[7].data);
  return true;
}

/**
 * @brief   根据can_id从table中找到对应的数据写入到data中
 * @param   uint16_t can_id 需要获取哪个数据的can_id
 * @param   uint64_t *data 获取对应can_id的数据
 * @retval  bool 获取成功(true)，获取失败(false)
 * @note
 */
bool protocol_table_get_data_by_canid(uint16_t can_id, uint64_t *data) {
  int32_t protocol_table_subscript;

  protocol_table_subscript = protocol_find_can_id(can_id);
  if (protocol_table_subscript < 0) {
    /* 没有从table中找到对应的can_id返回失败 */
    TLOGI(TAG, "protocol_block_package not find can_id\n");
    return false;
  }
  *data = s_table_point[protocol_table_subscript].frame_data.word_64;

  return true;
}

/**
 * @brief   根据canid获取协议表中的某个字节
 * @param   uint16_t can_id CANID号
 * @param   uint8_t byte_number byte号从0开始
 * @param   uint8_t *data 数据存储
 * @retval  ture 获取成功，false 获取失败
 * @note
 */
bool protocol_table_get_byte_by_canid(uint16_t can_id, uint8_t byte_number, uint8_t *data) {
  int32_t protocol_table_subscript;

  protocol_table_subscript = protocol_find_can_id(can_id);
  if (protocol_table_subscript < 0) {
    return false;
  }

  if (!protocol_byte_number_check(byte_number)) {
    return false;
  }

  *data = s_table_point[protocol_table_subscript].frame_data.byte[byte_number].data;

  return true;
}

/**
 * @brief   根据canid设置协议表中的某个字节
 * @param   uint16_t can_id CANID号
 * @param   uint8_t byte_number byte号从0开始
 * @param   uint8_t byte 要设置的数据
 * @retval  ture 设置成功，false 设置失败
 * @note    该函数只在数据更新回调中使用
 */
bool protocol_table_set_byte_by_canid(uint16_t can_id, uint8_t byte_number, uint8_t data) {
  int32_t protocol_table_subscript;

  protocol_table_subscript = protocol_find_can_id(can_id);
  if (protocol_table_subscript < 0) {
    return false;
  }

  if (!protocol_byte_number_check(byte_number)) {
    return false;
  }

  s_table_point[protocol_table_subscript].frame_data.byte[byte_number].data = data;

  return true;
}

uint32_t protocol_table_get_table_array_size(void) { return s_table_array_size; }